package com.example.demo2022.aop;

import com.alibaba.fastjson.JSONObject;
import com.example.demo2022.common.constant.GlobalConstant;
import com.example.demo2022.entity.OperatorLog;
import com.example.demo2022.entity.User;
import com.example.demo2022.service.IOperatorLogService;
import com.example.demo2022.util.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/************************************
 * @PACKAGE : com.example.demo2022.aop
 * @Author    :  叫我老伯
 * @Date    : 2022/5/30 22:21
 * @Desc    : 记录操作日志切面
 ***********************************/
@Aspect
@Component
@Slf4j
public class OperatorLogAop {
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private IOperatorLogService operatorLogService;

    //定义切点，注解作为切入点
    @Pointcut("execution(public * com.example.demo2022.controller..*.*(..))")
    public void logPoinCut() {

    }


    @Around("logPoinCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        OperatorLog operatorLog = new OperatorLog();
        String token = request.getHeader(GlobalConstant.HEADER_TOKEN);
        if(!StringUtils.isEmpty(token)){
            // 可以从session获取 / token获取
            // 从token中获取到用户ID
            User user = TokenUtil.getUser(token);
            operatorLog.setUserId(user.getId());
        }
        /**
         * 进行业务操作
         */
        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();
        String clz = joinPoint.getTarget().getClass().toString();
        operatorLog.setMethodName(clz +"."+ method.getName());
        operatorLog.setUrl(request.getRequestURI());
        //获取切入点方法参数
        Object[] objects = joinPoint.getArgs();
        String[] paramNames =  signature.getParameterNames();
        Map<String,Object> map = new HashMap<>();
        for (int i =0;i<paramNames.length;i++){
            map.put(paramNames[i],objects[i]);
        }
        // 入参转化成json
        operatorLog.setInParameter(JSONObject.toJSONString(map));
        // 执行目标方法  获取返回值
        Object r = joinPoint.proceed();
        // 如果我们封装了通用的返回结果可以直接转json
        operatorLog.setOutParameter(JSONObject.toJSONString(r.toString()));
        operatorLog.setCreateTime(LocalDateTime.now());
        // 插入数据库，操作日志：
        operatorLogService.save(operatorLog);
        return r;
    }
}
